From 396acf3bbbe00a192cb0ea0a9ccf91b1d8d2850b Mon Sep 17 00:00:00 2001 From: Fuwn <50817549+Fuwn@users.noreply.github.com> Date: Sat, 24 Jan 2026 13:09:50 +0000 Subject: Initial commit Created from https://vercel.com/new --- .../[websiteId]/segments/SegmentAddButton.tsx | 21 ++++++ .../[websiteId]/segments/SegmentDeleteButton.tsx | 60 +++++++++++++++ .../[websiteId]/segments/SegmentEditButton.tsx | 37 ++++++++++ .../[websiteId]/segments/SegmentEditForm.tsx | 86 ++++++++++++++++++++++ .../[websiteId]/segments/SegmentsDataTable.tsx | 24 ++++++ .../websites/[websiteId]/segments/SegmentsPage.tsx | 16 ++++ .../[websiteId]/segments/SegmentsTable.tsx | 38 ++++++++++ .../(main)/websites/[websiteId]/segments/page.tsx | 12 +++ 8 files changed, 294 insertions(+) create mode 100644 src/app/(main)/websites/[websiteId]/segments/SegmentAddButton.tsx create mode 100644 src/app/(main)/websites/[websiteId]/segments/SegmentDeleteButton.tsx create mode 100644 src/app/(main)/websites/[websiteId]/segments/SegmentEditButton.tsx create mode 100644 src/app/(main)/websites/[websiteId]/segments/SegmentEditForm.tsx create mode 100644 src/app/(main)/websites/[websiteId]/segments/SegmentsDataTable.tsx create mode 100644 src/app/(main)/websites/[websiteId]/segments/SegmentsPage.tsx create mode 100644 src/app/(main)/websites/[websiteId]/segments/SegmentsTable.tsx create mode 100644 src/app/(main)/websites/[websiteId]/segments/page.tsx (limited to 'src/app/(main)/websites/[websiteId]/segments') diff --git a/src/app/(main)/websites/[websiteId]/segments/SegmentAddButton.tsx b/src/app/(main)/websites/[websiteId]/segments/SegmentAddButton.tsx new file mode 100644 index 0000000..7b70fee --- /dev/null +++ b/src/app/(main)/websites/[websiteId]/segments/SegmentAddButton.tsx @@ -0,0 +1,21 @@ +import { useMessages } from '@/components/hooks'; +import { Plus } from '@/components/icons'; +import { DialogButton } from '@/components/input/DialogButton'; +import { SegmentEditForm } from './SegmentEditForm'; + +export function SegmentAddButton({ websiteId }: { websiteId: string }) { + const { formatMessage, labels } = useMessages(); + + return ( + } + label={formatMessage(labels.segment)} + variant="primary" + width="800px" + > + {({ close }) => { + return ; + }} + + ); +} diff --git a/src/app/(main)/websites/[websiteId]/segments/SegmentDeleteButton.tsx b/src/app/(main)/websites/[websiteId]/segments/SegmentDeleteButton.tsx new file mode 100644 index 0000000..bb52a22 --- /dev/null +++ b/src/app/(main)/websites/[websiteId]/segments/SegmentDeleteButton.tsx @@ -0,0 +1,60 @@ +import { ConfirmationForm } from '@/components/common/ConfirmationForm'; +import { useDeleteQuery, useMessages } from '@/components/hooks'; +import { Trash } from '@/components/icons'; +import { DialogButton } from '@/components/input/DialogButton'; +import { messages } from '@/components/messages'; + +export function SegmentDeleteButton({ + segmentId, + websiteId, + name, + onSave, +}: { + segmentId: string; + websiteId: string; + name: string; + onSave?: () => void; +}) { + const { formatMessage, labels, FormattedMessage } = useMessages(); + const { mutateAsync, isPending, error, touch } = useDeleteQuery( + `/websites/${websiteId}/segments/${segmentId}`, + ); + + const handleConfirm = async (close: () => void) => { + await mutateAsync(null, { + onSuccess: () => { + touch('segments'); + onSave?.(); + close(); + }, + }); + }; + + return ( + } + title={formatMessage(labels.confirm)} + variant="quiet" + width="600px" + > + {({ close }) => ( + {name}, + }} + /> + } + isLoading={isPending} + error={error} + onConfirm={handleConfirm.bind(null, close)} + onClose={close} + buttonLabel={formatMessage(labels.delete)} + buttonVariant="danger" + /> + )} + + ); +} diff --git a/src/app/(main)/websites/[websiteId]/segments/SegmentEditButton.tsx b/src/app/(main)/websites/[websiteId]/segments/SegmentEditButton.tsx new file mode 100644 index 0000000..5c56cf1 --- /dev/null +++ b/src/app/(main)/websites/[websiteId]/segments/SegmentEditButton.tsx @@ -0,0 +1,37 @@ +import { useMessages } from '@/components/hooks'; +import { Edit } from '@/components/icons'; +import { DialogButton } from '@/components/input/DialogButton'; +import type { Filter } from '@/lib/types'; +import { SegmentEditForm } from './SegmentEditForm'; + +export function SegmentEditButton({ + segmentId, + websiteId, + filters, +}: { + segmentId: string; + websiteId: string; + filters?: Filter[]; +}) { + const { formatMessage, labels } = useMessages(); + + return ( + } + title={formatMessage(labels.segment)} + variant="quiet" + width="800px" + > + {({ close }) => { + return ( + + ); + }} + + ); +} diff --git a/src/app/(main)/websites/[websiteId]/segments/SegmentEditForm.tsx b/src/app/(main)/websites/[websiteId]/segments/SegmentEditForm.tsx new file mode 100644 index 0000000..c3529d9 --- /dev/null +++ b/src/app/(main)/websites/[websiteId]/segments/SegmentEditForm.tsx @@ -0,0 +1,86 @@ +import { + Button, + Form, + FormButtons, + FormField, + FormSubmitButton, + Label, + Loading, + TextField, +} from '@umami/react-zen'; +import { useMessages, useUpdateQuery, useWebsiteSegmentQuery } from '@/components/hooks'; +import { FieldFilters } from '@/components/input/FieldFilters'; +import { messages } from '@/components/messages'; + +export function SegmentEditForm({ + segmentId, + websiteId, + filters = [], + showFilters = true, + onSave, + onClose, +}: { + segmentId?: string; + websiteId: string; + filters?: any[]; + showFilters?: boolean; + onSave?: () => void; + onClose?: () => void; +}) { + const { data } = useWebsiteSegmentQuery(websiteId, segmentId); + const { formatMessage, labels, getErrorMessage } = useMessages(); + + const { mutateAsync, error, isPending, touch, toast } = useUpdateQuery( + `/websites/${websiteId}/segments${segmentId ? `/${segmentId}` : ''}`, + { + type: 'segment', + }, + ); + + const handleSubmit = async (formData: any) => { + await mutateAsync(formData, { + onSuccess: async () => { + toast(formatMessage(messages.saved)); + touch('segments'); + onSave?.(); + onClose?.(); + }, + }); + }; + + if (segmentId && !data) { + return ; + } + + return ( +
+ + + + {showFilters && ( + <> + + + + + + )} + + + + {formatMessage(labels.save)} + + +
+ ); +} diff --git a/src/app/(main)/websites/[websiteId]/segments/SegmentsDataTable.tsx b/src/app/(main)/websites/[websiteId]/segments/SegmentsDataTable.tsx new file mode 100644 index 0000000..c1ba82e --- /dev/null +++ b/src/app/(main)/websites/[websiteId]/segments/SegmentsDataTable.tsx @@ -0,0 +1,24 @@ +import { DataGrid } from '@/components/common/DataGrid'; +import { useWebsiteSegmentsQuery } from '@/components/hooks'; +import { SegmentAddButton } from './SegmentAddButton'; +import { SegmentsTable } from './SegmentsTable'; + +export function SegmentsDataTable({ websiteId }: { websiteId?: string }) { + const query = useWebsiteSegmentsQuery(websiteId, { type: 'segment' }); + + const renderActions = () => { + return ; + }; + + return ( + + {({ data }) => } + + ); +} diff --git a/src/app/(main)/websites/[websiteId]/segments/SegmentsPage.tsx b/src/app/(main)/websites/[websiteId]/segments/SegmentsPage.tsx new file mode 100644 index 0000000..cbe7a1c --- /dev/null +++ b/src/app/(main)/websites/[websiteId]/segments/SegmentsPage.tsx @@ -0,0 +1,16 @@ +'use client'; +import { Column } from '@umami/react-zen'; +import { WebsiteControls } from '@/app/(main)/websites/[websiteId]/WebsiteControls'; +import { Panel } from '@/components/common/Panel'; +import { SegmentsDataTable } from './SegmentsDataTable'; + +export function SegmentsPage({ websiteId }) { + return ( + + + + + + + ); +} diff --git a/src/app/(main)/websites/[websiteId]/segments/SegmentsTable.tsx b/src/app/(main)/websites/[websiteId]/segments/SegmentsTable.tsx new file mode 100644 index 0000000..4dbe511 --- /dev/null +++ b/src/app/(main)/websites/[websiteId]/segments/SegmentsTable.tsx @@ -0,0 +1,38 @@ +import { DataColumn, DataTable, type DataTableProps, Row } from '@umami/react-zen'; +import Link from 'next/link'; +import { SegmentDeleteButton } from '@/app/(main)/websites/[websiteId]/segments/SegmentDeleteButton'; +import { SegmentEditButton } from '@/app/(main)/websites/[websiteId]/segments/SegmentEditButton'; +import { DateDistance } from '@/components/common/DateDistance'; +import { useMessages, useNavigation } from '@/components/hooks'; + +export function SegmentsTable(props: DataTableProps) { + const { formatMessage, labels } = useMessages(); + const { websiteId, renderUrl } = useNavigation(); + + return ( + + + {(row: any) => ( + + {row.name} + + )} + + + {(row: any) => } + + + {(row: any) => { + const { id, name } = row; + + return ( + + + + + ); + }} + + + ); +} diff --git a/src/app/(main)/websites/[websiteId]/segments/page.tsx b/src/app/(main)/websites/[websiteId]/segments/page.tsx new file mode 100644 index 0000000..0d3faac --- /dev/null +++ b/src/app/(main)/websites/[websiteId]/segments/page.tsx @@ -0,0 +1,12 @@ +import type { Metadata } from 'next'; +import { SegmentsPage } from './SegmentsPage'; + +export default async function ({ params }: { params: Promise<{ websiteId: string }> }) { + const { websiteId } = await params; + + return ; +} + +export const metadata: Metadata = { + title: 'Segments', +}; -- cgit v1.2.3